package io.yizoo.system.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.yizoo.business.entity.biz_hrm_ei_basic;
import io.yizoo.business.entity.biz_hrm_ei_rel_org;
import io.yizoo.business.entity.biz_wms_goods_type;
import io.elm.core.CoreController;
import io.elm.core.HMapper;
import io.elm.core.saas.DSContext;
import io.elm.core.security.JwtUtils;
import io.yizoo.core.AliyunSmsUtil;
import io.yizoo.system.entity.*;
import io.elm.core.sys_codeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/system/login")
public class loginController extends CoreController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private io.yizoo.system.mapper.sys_menuMapper sys_menuMapper;
    @Autowired
    private sys_codeMapper sys_codeMapper;
    @Autowired
    private io.yizoo.system.mapper.yizoomanager_sys_trialMapper yizoomanager_sys_trialMapper;

    private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @PostMapping("/AuthLogin")
    public Object AuthLogin(@RequestBody String jsonStr) {
        List<Map<String,Object>> datas = DSContext.DATA_SET;
        try {
            String password = Ctor.getObjectNode(jsonStr).get("pwd").asText();
            String name = Ctor.getObjectNode(jsonStr).get("id").asText();
            //
            String dataKey = Ctor.GetCutKey(name);
            DSContext.clearDataSourceType();
            DSContext.setDataSourceType(dataKey);
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(name, password)
            );
            final String token = jwtUtils.generateToken(name);

            DSContext.setDataSourceType(dataKey);
            name = Ctor.GetCutUsername(name);
            sys_user user_mod = Ctor.HMapper.GetSingle(sys_user.class,
                    Ctor.DMaker().Selector
                            .putFactorItem("id", name)
                            .From(sys_user.class).Where("and user_name=#{id}").GetFactor()
            );
            if (!this.validatePassword(password) || user_mod.getInit_password() == 1) {
                return JsonResult(
                        new KV("token", token),
                        new KV("success", true),
                        new KV("authpage", user_mod.getInit_password() == 1 ? "pass_eidt" : "pass_eidt_1")
                );
            }

            //若有人员关联，那么几个字段值用人员表记录的对应字段值
            boolean eiOrgExist = false;
            List<Map<String,Object>> check_ei = Ctor.CoreMapper.USelect(
                    Ctor.DMaker().Selector
                            .putFactorItem("id", user_mod.getId())
                            .Select("uu.*,ei.id AS ei_id,ei.name AS ei_name,ei.sex AS ei_sex,ei.phone AS ei_phone,oo.id AS ei_org_id")
                            .From(sys_user.class,"uu")
                            .LeftJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                            .LeftJoin(biz_hrm_ei_rel_org.class,"rr","rr.ei_id = ei.id AND rr.pm='1' ")
                            .LeftJoin(sys_org.class,"oo","oo.id = rr.org_id ")
                            .Where("AND uu.id = #{id}","id")
                            .GetFactor());
            if(check_ei.size()==1 && check_ei.get(0).get("ei_id")!=null){
                Map<String,Object> item = check_ei.get(0);
                if(item.get("ei_name")!=null){user_mod.setNick_name(item.get("ei_name").toString());}
                if(item.get("ei_org_id")!=null){user_mod.setDept_id(item.get("ei_org_id").toString());eiOrgExist = true;}
                //if(item.get("ei_phone")!=null){user_mod.setPhonenumber(item.get("ei_phone").toString());}
                //if(item.get("ei_sex")!=null){user_mod.setSex(item.get("ei_sex").toString());}
            }

            sys_org org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                    Ctor.DMaker().Selector.From(sys_org.class, "t")
                            .putFactorItem("id", name)
                            .LeftJoin(sys_user.class, "a", "a.dept_id=t.id")
                            .Where("and a.user_name=#{id}").GetFactor()
            );
            if(eiOrgExist){
                org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                        Ctor.DMaker().Selector.From(sys_org.class, "t")
                                .putFactorItem("id", user_mod.getDept_id())
                                .Where("and t.id=#{id}").GetFactor()
                );
            }
            Object roles = Ctor.CoreMapper.USelect(
                    Ctor.DMaker(jsonStr).Selector.From(sys_role.class, "t")
                            .Select("t.*")
                            .putFactorItem("user_id", user_mod.getId())
                            .LeftJoin(sys_role_rel_user.class, "a", "a.role_id=t.id")
                            .Where("and a.user_id=#{user_id}").GetFactor()
            );
            String client ="电脑及移动端";
            if(Ctor.getObjectNode(jsonStr).has("client"))
            {
                client = Ctor.getObjectNode(jsonStr).get("client").asText();
            }
            Object menu_data = sys_menuMapper.SelectUserMenuTree(
                    Ctor.DMaker().Selector
                            .putFactorItem("user_id", user_mod.getId())
                            .putFactorItem("client", client)
                            .GetFactor()
            );
            return JsonResult(
                    new KV("token", token),
                    new KV("success", true),
                    new KV("authpage", ""),
                    new KV("menu", menu_data),
                    new KV("user",
                            new KV("name", user_mod.getNick_name())),
                    new KV("org",
                            new KV("name", org_mod.getName())),
                    new KV("role", roles),
                    new KV("system",
                            new KV("path", "/system/main"),
                            new KV("name", "主页"))
            );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DSContext.clearDataSourceType();
        }
        return null;
    }


    @PostMapping("/FreeLogin")
    public Object FreeLogin(@RequestBody String jsonStr) {
        try {
            String dh = Ctor.getObjectNode(jsonStr).get("dh").asText();
            String yzm = Ctor.getObjectNode(jsonStr).get("yzm").asText();
            String qymc = Ctor.getObjectNode(jsonStr).get("qymc").asText();
            String enc_yzm = Ctor.getObjectNode(jsonStr).get("enc_yzm").asText();
            String de_enc_yzm=AliyunSmsUtil.decrypt(enc_yzm);
            if(!yzm.equals(de_enc_yzm))
            {
                return JsonResult(
                        new KV("success", false),
                        new KV("msg", "验证码错误")
                );
            }
            //
            String name ="admin.free";
            String password ="Abcd@123";
            //
            String dataKey = Ctor.GetCutKey(name);
            DSContext.clearDataSourceType();
            DSContext.setDataSourceType(dataKey);
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(name, password)
            );
            final String token = jwtUtils.generateToken(name);

            DSContext.setDataSourceType(dataKey);
            name = Ctor.GetCutUsername(name);
            //
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String formattedDateTime = now.format(formatter);
            yizoomanager_sys_trialMapper.insertData(
                    Ctor.DMaker(jsonStr).Insertor
                            .putFactorItem("id", UUID.randomUUID().toString())
                            .putFactorItem("phone", dh)
                            .putFactorItem("org", qymc)
                            .putFactorItem("login_time", formattedDateTime)
                            .GetFactor()
            );
            //
            sys_user user_mod = Ctor.HMapper.GetSingle(sys_user.class,
                    Ctor.DMaker().Selector
                            .putFactorItem("id", name)
                            .From(sys_user.class).Where("and user_name=#{id}").GetFactor()
            );
            if (!this.validatePassword(password) || user_mod.getInit_password() == 1) {
                return JsonResult(
                        new KV("token", token),
                        new KV("success", true),
                        new KV("authpage", user_mod.getInit_password() == 1 ? "pass_eidt" : "pass_eidt_1")
                );
            }

            //若有人员关联，那么几个字段值用人员表记录的对应字段值
            boolean eiOrgExist = false;
            List<Map<String,Object>> check_ei = Ctor.CoreMapper.USelect(
                    Ctor.DMaker().Selector
                            .putFactorItem("id", user_mod.getId())
                            .Select("uu.*,ei.id AS ei_id,ei.name AS ei_name,ei.sex AS ei_sex,ei.phone AS ei_phone,oo.id AS ei_org_id")
                            .From(sys_user.class,"uu")
                            .LeftJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                            .LeftJoin(biz_hrm_ei_rel_org.class,"rr","rr.ei_id = ei.id AND rr.pm='1' ")
                            .LeftJoin(sys_org.class,"oo","oo.id = rr.org_id ")
                            .Where("AND uu.id = #{id}","id")
                            .GetFactor());
            if(check_ei.size()==1 && check_ei.get(0).get("ei_id")!=null){
                Map<String,Object> item = check_ei.get(0);
                if(item.get("ei_name")!=null){user_mod.setNick_name(item.get("ei_name").toString());}
                if(item.get("ei_org_id")!=null){user_mod.setDept_id(item.get("ei_org_id").toString());eiOrgExist = true;}
                //if(item.get("ei_phone")!=null){user_mod.setPhonenumber(item.get("ei_phone").toString());}
                //if(item.get("ei_sex")!=null){user_mod.setSex(item.get("ei_sex").toString());}
            }

            sys_org org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                    Ctor.DMaker().Selector.From(sys_org.class, "t")
                            .putFactorItem("id", name)
                            .LeftJoin(sys_user.class, "a", "a.dept_id=t.id")
                            .Where("and a.user_name=#{id}").GetFactor()
            );
            if(eiOrgExist){
                org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                        Ctor.DMaker().Selector.From(sys_org.class, "t")
                                .putFactorItem("id", user_mod.getDept_id())
                                .Where("and t.id=#{id}").GetFactor()
                );
            }
            Object roles = Ctor.CoreMapper.USelect(
                    Ctor.DMaker(jsonStr).Selector.From(sys_role.class, "t")
                            .Select("t.*")
                            .putFactorItem("user_id", user_mod.getId())
                            .LeftJoin(sys_role_rel_user.class, "a", "a.role_id=t.id")
                            .Where("and a.user_id=#{user_id}").GetFactor()
            );
            Object menu_data = sys_menuMapper.SelectUserMenuTree(
                    Ctor.DMaker().Selector.putFactorItem("user_id", user_mod.getId()).GetFactor()
            );
            return JsonResult(
                    new KV("token", token),
                    new KV("success", true),
                    new KV("authpage", ""),
                    new KV("menu", menu_data),
                    new KV("user",
                            new KV("name", user_mod.getNick_name())),
                    new KV("org",
                            new KV("name", org_mod.getName())),
                    new KV("role", roles),
                    new KV("system",
                            new KV("path", "/system/main"),
                            new KV("name", "主页"))
            );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DSContext.clearDataSourceType();
        }
        return null;
    }

    @PostMapping("/FreeYZM")
    public Object FreeYZM(@RequestBody String jsonStr) {
        String dh = Ctor.getObjectNode(jsonStr).get("dh").asText();
        boolean tg = AliyunSmsUtil.validatePhoneNumber(dh);
        if (!tg) {
            return null;
        }
        String yzm = AliyunSmsUtil.generateRandomCode(4);
        String enc_yzm = AliyunSmsUtil.encrypt(yzm);
        AliyunSmsUtil.SendSmsYZM(dh,yzm);
        return JsonResult(
                new KV("yzm", enc_yzm)
        );
    }

    @PostMapping("/GetUserMenu")
    public Object GetUserMenu() {
        Object data = sys_menuMapper.SelectUserMenuTree(
                Ctor.DMaker().Selector
                        .putFactorItem("user_id",Ctor.getCurrentUserId())
                        .GetFactor()
        );
        return JsonResult(data);
    }

    @PostMapping("/Logout")
    public Object Logout() {
        Object data = sys_menuMapper.SelectUserMenuTree(
                Ctor.DMaker().Selector
                        .putFactorItem("user_id", Ctor.getCurrentUserId())
                        .GetFactor()
        );
        return JsonResult(data);
    }
    @PostMapping("/GetUserRole")
    public Object GetUserRole() {
        Object data = Ctor.CoreMapper.USelect (
                Ctor.DMaker().Selector.From(sys_role.class,"t")
                        .Select("t.id")
                        .putFactorItem("user_id",Ctor.getCurrentUserId())
                        .LeftJoin(sys_role_rel_user.class,"a","a.role_id=t.id")
                        .Where("and a.user_id=#{user_id}").GetFactor()
        );
        return JsonResult(data);
    }
    @PostMapping("/EditPassword")
    public Object EditPassword(@RequestBody String jsonStr) {
        ObjectNode node = Ctor.getObjectNode(jsonStr);
        if(this.validatePassword(node.get("newPass").asText()))
        {
            ObjectNode mod_node = (new ObjectMapper()).createObjectNode();
            mod_node.put("id", Ctor.getCurrentUserId());
            mod_node.put("password",passwordEncoder.encode(node.get("newPass").asText()));
            mod_node.put("init_password",0);
            Ctor.HMapper.Upsert(sys_user.class,mod_node,null);
            return JsonResult(new KV("status","success"));
        }
        else
        {
            return JsonResult(new KV("status","error"));
        }
    }


    private boolean validatePassword(String password) {
        String SPECIAL_CHAR_REGEX = "!@#$%^&*()_+-=[]{}|;:'\",.<>/?";
        if (password == null || password.length() < 8) {
            return false;
        }

        boolean hasUpperCase = false;
        boolean hasLowerCase = false;
        boolean hasDigit = false;
        boolean hasSpecialChar = false;

        for (char ch : password.toCharArray()) {
            if (Character.isUpperCase(ch)) {
                hasUpperCase = true;
            } else if (Character.isLowerCase(ch)) {
                hasLowerCase = true;
            } else if (Character.isDigit(ch)) {
                hasDigit = true;
            } else if (SPECIAL_CHAR_REGEX.indexOf(ch) >= 0) {
                hasSpecialChar = true;
            }
            if (hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar) {
                return true;
            }
        }

        return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
    }
    @PostMapping("/GetOrgTree")
    public Object GetTree(@RequestBody String jsonStr) throws Exception {
        Map<String, Object> factor = Ctor.DMaker(jsonStr).Selector
                .From(sys_org.class)
                .IsWhere("and name like CONCAT('%', #{name}, '%')","name")
                .IsPage()
                .GetFactor();
        HMapper.PageData data = Ctor.HMapper.GetTree(factor);
        return JsonResult(data);
    }

    @PostMapping("/GetOrgPath")
    public Object GetPath(@RequestBody String jsonStr) {
        Object data = Ctor.HMapper.GetPath(
                Ctor.DMaker(jsonStr).Selector
                        .From(sys_org.class)
                        .Select("id,pid,name")
                        .IsWhere("and id=#{id}","id")
                        .GetFactor());
        return JsonResult(data);
    }
    @PostMapping("/GetUserList")
    public Object GetUserList(@RequestBody String jsonStr) {
        List<Map<String,Object>> user_list = Ctor.CoreMapper.USelect(
                Ctor.DMaker(jsonStr).Selector
                        .Select("uu.id,uu.nick_name as name")
                        .From(sys_user.class,"uu")
                        .Where(" AND uu.nick_name LIKE CONCAT('%', #{name}, '%')","name")
                        .OrderBy("uu.user_name")
                        .GetFactor());
        return user_list;
    }
    @PostMapping("/GetUserListbyID")
    public Object GetUserListbyID(@RequestBody String jsonStr) {
        List<Map<String,Object>> user_list = Ctor.CoreMapper.USelect(
                Ctor.DMaker(jsonStr).Selector
                        .Select("uu.id,uu.nick_name as name")
                        .From(sys_user.class,"uu")
                        .Where(" AND id=#{id}","id")
                        .OrderBy("uu.user_name")
                        .GetFactor());
        return user_list;
    }
    @PostMapping("/GetGoodsTypeTree")
    public Object GetGoodsTypeTree(@RequestBody String jsonStr) throws Exception {
        Map<String, Object> factor = Ctor.DMaker(jsonStr).Selector
                .From(biz_wms_goods_type.class)
                .IsWhere("and type like CONCAT('%', #{name}, '%')","name")
                .IsPage()
                .GetFactor();
        HMapper.PageData data = Ctor.HMapper.GetTree(factor);
        return JsonResult(data);
    }

    @PostMapping("/GetGoodsTypePath")
    public Object GetGoodsTypePath(@RequestBody String jsonStr) {
        Object data = Ctor.HMapper.GetPath(
                Ctor.DMaker(jsonStr).Selector
                        .From(biz_wms_goods_type.class)
                        .Select("id,pid,type")
                        .IsWhere("and id=#{id}","id")
                        .GetFactor());
        return JsonResult(data);
    }

    @PostMapping("/GetUserEi")
    public Object GetUserEi() {
        Object data = Ctor.CoreMapper.USelect (
                Ctor.DMaker().Selector.From(biz_hrm_ei_basic.class,"t")
                        .Select("t.emp_code")
                        .putFactorItem("user_id",Ctor.getCurrentUserId())
                        .LeftJoin(sys_user.class,"a","a.emp_code=t.emp_code")
                        .Where("and a.id=#{user_id}").GetFactor()
        );
        return JsonResult(data);
    }
}
